package com.winit.openapi.util;

import java.net.Inet4Address;
import java.net.InetAddress;
import java.net.NetworkInterface;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;

import com.winit.openapi.oauth.entity.APISystemConfigEntity;
import com.winit.openapi.oauth.manager.APIClientManager;
import com.winit.openapi.oauth.manager.APISystemConfigManager;
import com.winit.openapi.oauth.vo.APIClientVo;

@Service("apiSysConfigUtil")
public class APISysConfigUtil {

    private static final Logger                             logger               = LoggerFactory.getLogger(APISysConfigUtil.class);

    /**
     * 同步系统配置项延迟时间
     */
    private static final long                               INITIAL_CONFIG_DELAY = 0;
    /**
     * 同步系统配置项周期
     */
    private static final long                               CONFIG_PERIOD_PERIOD = 20;
    @Resource
    private APISystemConfigManager                          apiSystemConfigManager;
    @Resource
    private APIClientManager                                APIClientManager;

    private static final Map<String, APISystemConfigEntity> configMap            = new ConcurrentHashMap<String, APISystemConfigEntity>();

    private static final Map<String, APIClientVo>           clientMap            = new ConcurrentHashMap<String, APIClientVo>();

    private static ScheduledExecutorService                 executor             = Executors.newScheduledThreadPool(1);

    private static volatile boolean                         isStart              = false;

    private static String                                   localIP              = null;

    private static volatile boolean                         isRecheckSign        = true;

    private static boolean                                  isDebug              = false;

    private void synSysConfig() {
        Map<String, APISystemConfigEntity> map = new HashMap<String, APISystemConfigEntity>();
        try {
            map = apiSystemConfigManager.findAll();
            if (map == null || map.size() == 0) {
                return;
            }
        } catch (Exception e) {
            logger.error("API-synSysConfig异常:" + e);
            return;
        }
        // 当数据不一致时，说明数据库进行了添加或删除操作，需要更新本地缓存
        if (!map.keySet().equals(configMap.keySet())) {
            logger.info("同步系统配置项，清除本地缓存...");
            configMap.clear();
        }
        configMap.putAll(map);
        String signFlag = getConfigValueByKey("API_RECHECK_SIGN_FLAG");
        if (StringUtils.isNotBlank(signFlag)) {
            isRecheckSign = Boolean.valueOf(signFlag).booleanValue();
        }
        String logFlag = getConfigValueByKey("API_LOG_DEBUG_FLAG");
        if (StringUtils.isNotBlank(logFlag)) {
            isDebug = Boolean.valueOf(logFlag).booleanValue();
        }
        if (isDebug) {
            logger.info("同步系统配置项完成.threadId:" + Thread.currentThread().getId() + " size=" + configMap.size());
        }

    }

    private boolean checkWhiteList(String configKey) {

        String value = getConfigValueByKey(configKey);
        if (StringUtils.isBlank(value)) {
            logger.warn("获取" + configKey + "白名单配置项失败.");
            return false;
        } else if ("all".equalsIgnoreCase(value)) {
            return true;

        }
        String[] arr = value.split("\\,");
        List<String> ipList = Arrays.asList(arr);

        if (isDebug) {
            logger.info("获取" + configKey + "结果:" + value);
        }
        return ipList.contains(localIP);
    }

    private void synClientConfig() {
        Map<String, APIClientVo> map = new HashMap<String, APIClientVo>();
        try {
            map = APIClientManager.findAll();
            if (map == null || map.size() == 0) {
                return;
            }
        } catch (Exception e) {
            logger.error("API-synClientConfig异常:" + e);
            return;
        }
        // 如果键发生变更则清除本地缓存
        if (!map.keySet().equals(clientMap.keySet())) {
            logger.info("同步Client配置项，清除本地缓存...");
            clientMap.clear();
        }
        clientMap.putAll(map);
        if (isDebug) {
            logger.info("同步client信息完成.threadId:" + Thread.currentThread().getId() + " size=" + clientMap.size());
        }
    }

    /**
     * 根据key查询key对应的配置项值
     * 
     * @param key
     * @return
     */
    public String getConfigValueByKey(String configKey) {
        if (configMap.isEmpty()) {
            doSynConfig();
        }
        APISystemConfigEntity entity = null;
        int retryTimes = 5;
        for (int i = 0; i < retryTimes; i++) {
            entity = configMap.get(configKey);
            if (entity != null) {
                if (i >= 1) {
                    logger.info("缓存查询系统配置项:" + configKey + " retryTimes：" + i);
                }
                return entity.getConfigValue();
            }

        }
        logger.warn("缓存查询系统配置项失败，key:" + configKey + " retryTimes:" + retryTimes);
        entity = apiSystemConfigManager.getEntityByKey(configKey);

        if (entity == null) {
            logger.warn("查询系统配置项失败，不存在的key:" + configKey);
            return null;
        }

        return entity.getConfigValue();

    }

    /**
     * 根据clientkey查询client
     * 
     * @param key
     * @return
     */
    public APIClientVo getClientByKey(String clientKey) {
        if (clientMap.isEmpty()) {
            doSynConfig();
        }

        APIClientVo clientVo = null;
        int retryTimes = 5;
        for (int i = 0; i < retryTimes; i++) {
            clientVo = clientMap.get(clientKey);
            if (clientVo != null) {
                if (i >= 1) {
                    logger.info("缓存查询client信息：" + clientKey + " retryTimes：" + i);
                }
                return clientVo;
            }

        }
        logger.warn("缓存查询client失败，clientKey:" + clientKey + " retryTimes:" + retryTimes);
        clientVo = APIClientManager.selectByClientKey(clientKey);

        if (clientVo == null) {
            logger.warn("查询client失败，不存在的clientKey:" + clientKey);
            return null;
        }

        return clientVo;

    }

    private void doSynConfig() {
        if (isStart) {
            return;
        }
        isStart = true;
        executor.scheduleAtFixedRate(new Runnable() {

            @Override
            public void run() {
                try {
                    if (isDebug) {
                        logger.info("API配置同步任务开始...");
                    }
                    synSysConfig();
                    synClientConfig();
                } catch (Throwable e) {
                    logger.error("同步任务失败：" + e);
                }

            }
        }, INITIAL_CONFIG_DELAY, CONFIG_PERIOD_PERIOD, TimeUnit.SECONDS);
    }

    /**
     * 判断当前机器是否支持OAuth2.0认证机制
     * 
     * @return
     */
    public boolean isOAuth2Support() {
        if (StringUtils.isBlank(localIP)) {
            initLocalIp();
        }

        return checkWhiteList("API_AUTH_WHITE_IP_LIST");
    }

    /**
     * 判断当前机器是否支持OAuth2.0认证机制
     * 
     * @return
     */
    public boolean isOutboundOrderSupport() {
        if (StringUtils.isBlank(localIP)) {
            initLocalIp();
        }

        return checkWhiteList("API_OUTBOUND_ORDER_ADAPTED_WHITE_IP_LIST");
    }

    public static boolean isRecheckSign() {

        return isRecheckSign;

    }

    public static boolean isDebug() {

        return isDebug;

    }

    public boolean isNotErrorCodeAdapted(String action) {
        String value = getConfigValueByKey("API_AD_ERROR_CODE_NOT_ADAPTED_ACTION_LIST");
        if (StringUtils.isBlank(value)) {
            return false;
        } else if ("all".equalsIgnoreCase(value)) {
            return true;
        }
        String[] arr = value.split("\\,");
        List<String> actionList = Arrays.asList(arr);
        return actionList.contains(action);

    }

    public boolean isRegisterProductAdapted() {
        String flag = getConfigValueByKey("API_REGISTER_PRODUCT_ADAPTED_FLAG");
        if (StringUtils.isBlank(flag)) {
            return false;
        }
        return "true".equalsIgnoreCase(flag);
    }

    public boolean isQueryWarehouseAdapted() {
        String flag = getConfigValueByKey("API_QUERY_WAREHOUSE_ADAPTED_FLAG");
        if (StringUtils.isBlank(flag)) {
            return false;
        }
        return "true".equalsIgnoreCase(flag);
    }
    
    public boolean isWarehouseInventoryAdapted() {
        String flag = getConfigValueByKey("API_QUERY_WAREHOUSE_INVENTORY_ADAPTED_FLAG");
        if (StringUtils.isBlank(flag)) {
            return false;
        }
        return "true".equalsIgnoreCase(flag);
    }

    private void initLocalIp() {
        try {
            Enumeration<NetworkInterface> allNetInterfaces = NetworkInterface.getNetworkInterfaces();
            while (allNetInterfaces.hasMoreElements()) {
                NetworkInterface netInterface = allNetInterfaces.nextElement();
                Enumeration<InetAddress> addresses = netInterface.getInetAddresses();
                while (addresses.hasMoreElements()) {
                    InetAddress ip = addresses.nextElement();
                    if (ip != null && ip instanceof Inet4Address && !ip.isLoopbackAddress()
                        && ip.getHostAddress().indexOf(":") == -1) {
                        logger.info("本机的IP = " + ip.getHostAddress());
                        localIP = ip.getHostAddress();
                    }
                }
            }
        } catch (Exception e) {
            logger.warn("获取本机IP地址异常：" + e);
        }
    }
}
